A More Complicated Example

Now, let's make the slave process a little bit more interesting. Let's assume that we have nprocs slaves with ids 0, 1, 2, ... nprocs -1. And, we want to write a program in which every process sends a single message to every other slave, and then receives a message from every other slave. We might alter the code for the slave procedure to be the following:


\begin{example}
slave()
\{
char *incoming, *msg = ''hello'';
int myid, size,...
...%d\verb+\n+'',myid,incoming,from);
p4_msg_free(incoming);
\}
\}
\end{example}

This program demonstrates several features of p4's support for message-passing. Before we get into the specifics however, let's examine the overall logic of the program. Each process determines its own id and the total number of processes executing in this run (including process 0). Then, in the first for-loop, each process sends a single message to each of the other processes. Finally, in the second for-loop, each process receives a message from each of the other processes.

The p4_send call requires 4 arguments:

The use of p4_recv is slightly more complicated. First, we assign -1 to each of the parameters type and from. This is done because -1 represents a wildcard value indicating we are willing to receive a message of any type from any process. Here, we could have coded type to be 100, and specified from equal to the value of i each time through the loop (skipping our own id). By setting incoming to NULL, we have also indicated to p4_recv that we do not have a buffer in which to place the received message, so p4_recv should obtain a buffer for us and place the message in that buffer. p4_recv treats these three parameters as both input and output values. Thus, it alters the value of each such that type and from indicate the type of message received and the id of the process that sent it. The value of incoming is altered to point to the buffer where the message was placed. The size parameter is strictly an output parameter and indicates the size of the received message. It is possible for the user to provide his own buffer; this will be demonstrated later.

deallocating buffers Finally, note that p4_msg_free frees the message buffer obtained by p4_recv. The procedure p4_msg_free should be called only after the contents of the message are no longer needed. P4_msg_free should be used to free these buffers because, although a user only sees the data portion of a message, p4 internally represents a message as a structured data item.

To compile and link this program for execution, you need to create a makefile. We will assume that you have installed p4 in /usr/local/p4 and that you have typed the program above into a file name p4simple.c in the directory /home/mylogin/p4pgms.

To build your makefile, copy the file
\begin{example}
/usr/local/p4/messages/makefile.proto
\end{example}
into your working directory. This is a prototype makefile that contains machine-independent information, and which p4 can use to build a machine-specific makefile for your program. This prototype makefile contains information about several sample programs that demonstrate message-passing in p4. If you edit this file, you will see information for making a program named sr_test. Do a global change of sr_test to p4simple. You should also change the value of P4_HOME_DIR. It should contain the full pathname of the p4 system, e.g. /usr/local/p4. Now change directories to /usr/local/p4 and type:


\begin{example}
make makefiles MACHINE=<machine_type> DIRS=/home/mylogin/p4pgms
\end{example}
where <your_machine_type> is the machine type that you specified when you installed p4 on your machine. Now, you should be able to change back to your directory and see a file named Makefile there. You should then be able to type:


\begin{example}
make p4simple
\end{example}

There is one last piece missing before you can execute your program. Recall that p4_create_procgroup needs to know how many processes to start and where to start them; it reads a file (called a procgroup file) to gather this information. p4 always assumes that you have a master process, and that you describe the slave processes (process groups) in the procgroup file. You can name a procgroup file any name you choose, but procgroup is the default name. The information contained in procgroup files can get fairly involved, but if you have a computer that supports shared memory among processes, then you can code a very simple example at first.

Let us suppose first that you want to run your program on a network of workstations. Then your procgroup should look something like:


\begin{example}
local O
some.network.machine 1 /home/me/p4progs/p4simple
\end{example}

This file indicates that you wish to run only the master on the local machine (the one you are logged into when you execute the program) and one slave on the machine some.network.machine.

Now, all you have to do to run your program is type:


\begin{example}
p4simple
\end{example}

You should see a line printed each time a process receives a message from another process (on some machines, there may be a restriction that only one process can do I/O, however such restrictions are not common). Experiment by changing the number of slaves indicated in the procgroup file.

You may notice that even a small p4 program becomes large when linked with the p4 library. You might consider using strip to reduce the size or removing -g from the CFLAGS in the makefile.

Command-Line Arguments,The p4 Function Library,Developing a Simple p4 Program,Top